#include "Stack.h"
#include "Operation.h"
#include <sstream>
#include <cmath>

/*******************************************************************************
*类名：Stack
*功能：逆波兰算法实现
*接口：getPostfix(); 获取后缀表达式对外接口
*     getResult();  获取计算结果对外接口
*     setPostfix(QString exp); 中缀转后缀对外接口
*     setCalResults(); 计算表达式对外接口
*     clearPostfix(); 清除 m_Postfix 中后缀表达式接口
*作者：韦锴祖
*日期：2018年12月8号
********************************************************************************/

Stack::Stack()
{
	m_Postfix.empty();
	m_Result = NULL;
	oper = new Operation;	
}

/**
* 功能：析构函数
* 参数：
* 作者：韦锴祖
* 日期：2018-12-26
**/
Stack::~Stack()
{
	delete oper;
}

/**< 获取后缀表达式对外接口 */
string Stack::getPostfix()
{
	return this->m_Postfix;
}

/**< 获取计算结果对外接口 */
double Stack::getResult()
{
	return this->m_Result;
}

/**< 中缀转后缀对外接口 */
void Stack::setPostfix(string exp)
{
	toPostfix(exp);
}

/**< 计算表达式对外接口 */
void Stack::setCalResults()
{
	calResults();
}

/**< 清除 m_Postfix 容器中的后缀表达式对外接口 */
void Stack::clearPostfix()
{
	m_Postfix.clear();
}

/**
* 功能：string转double
* 参数：s 输入的string
* 作者：韦锴祖
* 日期：2019-1-8
**/
double Stack::convertStringToDouble(const string &s)
{
	double val;
	stringstream ss;
	ss << s;
	ss >> val;
	return val;

}

/**
* 功能：定义运算符的优先级
* 参数：ch 输入的运算符
* 作者：韦锴祖
* 日期：2018-12-8
**/
int Stack::getPriority(const char ch)
{
	switch (ch)
	{
	case '#':
	case '(':return 0;
	case '+':
	case '-':return 1;
	case '*':
	case '/':
	case '%':return 2;
	case '!':
	case '^':return 3;
	}
	return 0;
}

/**
* 功能：中缀表达式转化为后缀表达式
* 参数：strExp 输入的中缀表达式
*      left 左括号个数
*      m_Postfix 存储后缀表达式的容器
*      opStack  运算符栈
* 作者：韦锴祖
* 日期：2018-12-8
**/
void Stack::toPostfix(string strExp)
{
	opStack.push('#');
	for (unsigned int i = 0; i < strExp.length(); i++)                                 /**< 遍历整个表达式 */
	{
		if ((strExp[i] >= '0' && strExp[i] <= '9') || strExp[i] == '.')       /**< 如果是数字或者小数点，则直接进入容器m_Postfix末尾 */
		{
			m_Postfix.push_back(strExp[i]);
		}
		else if (strExp[i] == '(')                                           /**< 如果是'('则直接进入运算符栈 */
		{
			opStack.push(strExp[i]);
		}
		else if (strExp[i] == ')')                                           /**< 如果是')'则判断栈顶是不是'(' */
		{
				m_Postfix.push_back(' ');                                    /**< 往postfix容器末尾加入一个空格 */
				while (opStack.top() != '(')                                 /**< 循环判断 */
				{
					m_Postfix.push_back(opStack.top());                      /**< 把运算符的栈顶出站，加入到m_Postfix */
					opStack.pop();
				}
			opStack.pop();                                                   /**< 栈顶直接出栈 */
		}
		/**< 对'-'号进行特殊处理，实现负数功能 */
		else if (strExp[i] == '-' && i == 0)                                 /**< 如果遍历到'-'，而且上 i=0 ，则直接进入m_Postfix */
		{
			m_Postfix.push_back(strExp[i]);
		}
		else if (strExp[i] == '-' && strExp[i - 1] == '(')                   /**< 如果遍历到'-'，而且上一字符为'('，则直接进入m_Postfix */
		{
			m_Postfix.push_back(strExp[i]);
		}
		else if (getPriority(strExp[i]) > getPriority(opStack.top()))        /**< 如果遍历到的运算符优先级大于运算符栈顶元素，运算符进栈 */
		{
			m_Postfix.push_back(' ');
			opStack.push(strExp[i]);
		}
		else
		{
			m_Postfix.push_back(' ');
			while (getPriority(strExp[i]) <= getPriority(opStack.top()))     /**< 把运算符栈里面优先级比当前符号高的出栈 */
			{
				m_Postfix.push_back(opStack.top());
				opStack.pop();
				m_Postfix.push_back(' ');
			}
			opStack.push(strExp[i]);                                         /**< 直到栈里面没有比遍历到的符号优先级高是，运算符进栈 */
		}
	}
	while (opStack.top() != '#')                                             /**< 遍历结束后，如果运算符栈顶不是‘#’时，把栈顶元素循环出栈放入m_Postfix */
	{
		char c = opStack.top();
		opStack.pop();
		m_Postfix.push_back(' ');
		m_Postfix.push_back(c);
	}
}

/**
* 功能：计算后缀表达式
* 参数：tem 暂时存放数字的容器
*      num 存放运算结果的栈
*      m_Postfix 存储后缀表达式的容器
*      m_Result  存放最终运算结果的容器
*      opStack  运算符栈
* 作者：韦锴祖
* 日期：2018-12-8
**/

#if 1
void Stack::calResults()
{
	stack<double> num;                                                              /**< 定义存放运算结果的栈 */
	string tem;                                                                     /**< 定义暂时存放数字的容器 */
	for (unsigned int i = 0; i < m_Postfix.size(); i++)                                      /**< 遍历后缀表达式 */
	{
		if ((m_Postfix[i] >= '0' && m_Postfix[i] <= '9') || m_Postfix[i] == '.')    /**< 如果是数字或者小数点，则压入tem容器的最后面 */
		{
			tem.push_back(m_Postfix[i]);
		}
		else if (m_Postfix[i] == ' ')                                               /**< 遍历到空格 */
		{
			if (!tem.empty())                                                       /**< 如果tem容器不为空，则把tem里面的值装换为double类型放入num栈中，并清空tem */
			{
				num.push(convertStringToDouble(tem));
				//num.push(stod(tem));
				tem.clear();
			}
		}

		/**< 对'-'进行特殊处理，实现负数运算 */
		else if (m_Postfix[i] == '-' && (m_Postfix[i+1] >= '0' && m_Postfix[i+1] <= '9'))  /**< 如果遍历到"-"并且它的下一个字符为数字，"-"直接压入tem与后面的数字绑定在一起作为负数 */
		{
			tem.push_back(m_Postfix[i]);
		}
		else if (m_Postfix[i] == '!')                                              /**< 遍历到"!"，则进行阶乘运算 */
		{
			double a = num.top();
			num.pop();
			num.push(oper->OperationFac(a));
		}
		else                                                                       /**< 遍历到运算符，则从num栈中提取两个栈顶元素出来运算 */
		{
			double b = num.top();
			num.pop();
			double c = num.top();
			num.pop();
			switch (m_Postfix[i])                     
			{
			case '+':num.push(oper->OperationAdd(c, b)); break;
			case '-':num.push(oper->OperationSub(c, b)); break;
			case '*':num.push(oper->OperationMuti(c, b)); break;
			case '/':num.push(oper->OperationDivi(c, b)); break;
			case '^':num.push(oper->OperationPow(c, b)); break;
			case '%':num.push(oper->OperationMod(c, b)); break;
			}
		}

	}
	if (num.empty())                                                               /**< 如果num栈为空，把tem容器的值赋值给result */
	{
		//m_Result = stod(tem);
		//m_Result = atof(tem.c_str());
		m_Result = convertStringToDouble(tem);
		tem.clear();
	}

	else
	{
		m_Result = num.top();
	}
}
#endif

